import React, { Component, createRef } from "react";
import spine from "../spine/runtime/spine-widget";
import CircularProgress from "@material-ui/core/CircularProgress";
import Backdrop from "@material-ui/core/Backdrop";
import hammer from "hammerjs";
import GIF from "gif.js";
export class Spine extends Component {
  rootRef;
  delta = { x: 0, y: 0 };
  constructor(props) {
    super(props);
    this.rootRef = createRef();
    this.wheelHandler = this.wheelHandler.bind(this);
    this.isFirefox = navigator.userAgent.indexOf("Firefox") !== -1;
  }
  ensureEncoder(ws, name, progress, success) {
    this.encoder = new GIF({
      background: "#00",
      quality: 1,
      height: 1000,
      width: 1000,
      workers: 4,
      workerScript: ws,
      debug: true,
      repeat: -1,
    });
    this.encoder.gifFilename = name;
    this.encoder.on("finished", (blob) => {
      const dom = document.createElement("a");
      dom.href = URL.createObjectURL(blob);
      dom.download = this.encoder.gifFilename;
      dom.click();
      success();
    });
    this.encoder.on("progress", (num) => {
      console.log(num);
      progress(num);
    });
  }
  reset() {
    this.skeleton.x = 500;
    this.skeleton.y = 200;
  }
  wheelHandler(e) {
    e.preventDefault();
    let delta = this.isFirefox ? e.deltaY / 30 : e.deltaY * -0.001;
    if (this.widget) {
      if (this.widget.config.scale + delta <= 0) {
        return;
      }
      this.widget.config.scale += delta;
      this.widget.load();
    }
  }
  render() {
    return (
      <div
        style={{
          width: 1000 * this.props.scale,
          height: 1000 * this.props.scale,
          overflow: "hidden",
        }}
      >
        <Backdrop
          open={this.props.loading}
          style={{
            position: "absolute",
            width: 1000 * this.props.scale,
            height: 1000 * this.props.scale,
            zIndex: 1,
            top: "inherit",
            left: "inherit",
            right: "inherit",
            bottom: "inherit",
          }}
        >
          <CircularProgress />
        </Backdrop>
        <div
          style={{
            width: 1000,
            height: 1000,
            transform: `scale(${this.props.scale},${this.props.scale})`,
            transformOrigin: "top left",
          }}
          ref={this.rootRef}
        ></div>
      </div>
    );
  }
  componentWillUnmount() {
    this.mc.destroy();
    this.rootRef.current.removeEventListener("wheel", this.wheelHandler);
  }
  loadWidget(json, path, ani, hex, loop, skin, speed, cb) {
    this.widget = new spine.SpineWidget(this.rootRef.current, {
      jsonContent: json,
      atlas: path,
      animation: ani,
      backgroundColor: "#" + hex,
      debug: false,
      loop: loop,
      skin: skin,
      x: 500,
      y: 200,
      fitToCanvas: false,
      premultipliedAlpha: true,
      success: (widget) => {
        console.log(widget);
        widget.state.timeScale = speed;
        this.widget = widget;
        this.skeleton = widget.skeleton;
        widget.state.addListener({
          start: () => {
            if (this.gif) {
              this.startGif();
            }
          },
          complete: () => {
            if (this.gif) {
              this.gif = false;
              this.encoder.render();
            }
          },
        });
        cb(
          widget.skeleton.data.animations.map((v) => {
            return { duration: v.duration, name: v.name };
          })
        );
      },
    });
  }
  componentDidMount() {
    this.mc = new hammer(this.rootRef.current);
    this.mc.get("pinch").set({ enable: true });
    const mc = this.mc;
    mc.on("panstart", (ev) => {
      if (this.skeleton) {
        this.prev = { x: this.skeleton.x, y: this.skeleton.y };
      }
    });
    mc.on("panmove", (ev) => {
      if (this.skeleton && this.prev) {
        this.skeleton.x = this.prev.x + ev.deltaX / this.props.scale;
        this.skeleton.y = this.prev.y - ev.deltaY / this.props.scale;
      }
    });
    mc.on("panend", (ev) => {
      if (this.skeleton && this.prev) {
        this.skeleton.x = this.prev.x + ev.deltaX / this.props.scale;
        this.skeleton.y = this.prev.y - ev.deltaY / this.props.scale;
        this.prev = null;
      }
    });
    mc.on("pinchin", () => {
      if (this.widget.config.scale - 0.1 <= 0) {
        return;
      }
      this.widget.config.scale -= 0.1;
      this.widget.load();
    });
    mc.on("pinchout", () => {
      if (this.widget.config.scale + 0.1 <= 0) {
        return;
      }
      this.widget.config.scale += 0.1;
      this.widget.load();
    });
    this.rootRef.current.addEventListener("wheel", this.wheelHandler);
  }
  updateAnimation(ani, loop) {
    this.widget.state.setAnimation(0, ani, loop);
  }
  updateColor(r, g, b, a) {
    this.widget.backgroundColor.r = r / 255;
    this.widget.backgroundColor.g = g / 255;
    this.widget.backgroundColor.b = b / 255;
    this.widget.backgroundColor.a = a;
  }
  updateSpeed(speed) {
    this.widget.state.timeScale = speed;
  }
  buildGif(ani) {
    this.gif = true;
    this.updateAnimation(ani, false);
  }
  startGif() {
    if (!this.gif) {
      return;
    }
    this.encoder.addFrame(this.widget.canvas, { copy: true, delay: 1000 / 60 });
    requestAnimationFrame(() => {
      this.startGif();
    });
  }
}
